Skip to content

Feature/sdk improvements#14

Merged
wzul merged 24 commits into
mainfrom
feature/sdk-improvements
May 14, 2026
Merged

Feature/sdk improvements#14
wzul merged 24 commits into
mainfrom
feature/sdk-improvements

Conversation

@wzul
Copy link
Copy Markdown
Collaborator

@wzul wzul commented May 13, 2026

What does this change?

This PR represents a major architectural modernization of the CHIP PHP SDK, transitioning it from a basic Guzzle wrapper to a robust, enterprise-ready SDK (v2.0.0).

The Problem:
The previous version lacked strong type safety, had limited observability, and required developers to manually handle raw HTTP response parsing and Guzzle-specific exceptions. The absence of a structured CI/CD pipeline and static analysis made the codebase prone to regressions, while the reliance on legacy PHP versions prevented the use of modern language features.

The Solution:

  1. Language Modernization: Bumped minimum requirement to PHP 8.1, adopting constructor property promotion, explicit type hints, and match expressions.
  2. Resource-Based Architecture: Moved from a flat, trait-based client to a resource-oriented structure (e.g., $chip->purchases->create() instead of $chip->createPurchase()). This improves discoverability and organizes the API into logical domains (purchases, clients, webhooks, account, billing, etc.).
  3. Domain-Specific Exception Hierarchy: Refactored the core request logic to map HTTP errors to specific exceptions (AuthenticationException, ValidationException, NotFoundException, etc.). ValidationException now allows developers to call $e->getErrors() to retrieve granular API feedback.
  4. Observability & Logging: Integrated PSR-3 Logging support, allowing developers to inject any compliant logger to track the request/response lifecycle.
  5. Resilience & Retries: Added an internal RetryClient decorator using Guzzle middleware to provide exponential backoff for 429 (Rate Limit) and 5xx (Server Error) responses.
  6. Fluent Builder Pattern: Introduced PurchaseBuilder to provide a developer-friendly API for constructing complex Purchase models without manual nesting of objects.
  7. Model Refinement: Replaced the netresearch/jsonmapper dependency with native fromArray() static factories on models. Fixed property types (e.g., changing Product::$quantity from float to string|null) to accurately reflect API payloads and prevent precision issues.
  8. Pagination Iterators: Added iterate() methods to list endpoints, allowing developers to process large datasets without manually managing page tokens.
  9. Robust CI/CD:
    • GitHub Actions for multi-version testing (PHP 8.1–8.4).
    • PHPStan (Level 8) for strict static analysis.
    • PHP-CS-Fixer (PSR-12) for automated linting.
    • Automated Changelog validation and Release notes generation.

Asana / Jira / Trello task link

How to test

  1. Automated Suite: Run composer test to ensure the refactored exception mapping and new resource classes pass across PHP 8.1 through 8.4.
  2. Static Analysis: Run composer phpstan to verify that all new type hints and docblocks satisfy Level 8 analysis.
  3. Code Style: Run composer cs-check to ensure adherence to the new PSR-12 configuration.
  4. Resource Migration: Verify the new access pattern in a test script:
    $chip = new \Chip\ChipApi('brand-id', 'api-key');
    $methods = $chip->paymentMethods->list('MYR');
  5. Builder Verification:
    $purchase = \Chip\Builder\PurchaseBuilder::create()
        ->brandId('test-id')
        ->currency('MYR')
        ->addProduct('Item 1', 1000)
        ->build();
  6. Error Mapping: Manually trigger a 422 error and verify that ValidationException::getErrors() correctly parses the error payload.
  7. Pagination: Test the iterate() methods in ClientsResource or WebhooksResource against an account with multiple pages of data.

Potential Risks & Senior Review Items

  • Major Breaking Changes: This PR drops support for PHP < 8.1 and completely changes the public API surface. Existing integrations will break upon upgrading to v2.0.0. Review MIGRATION.md for completeness.
  • Model Property Types: Properties like Product::$quantity and Product::$tax_percent were changed from float to string|null. While this matches the API's string-based decimal representation, users performing direct arithmetic on these properties will now need to cast them to floats.
  • Retry Logic: Review the exponential backoff implementation in lib/Http/RetryClient.php. Ensure the default max retries (3) and timing won't lead to excessive execution times in synchronous request cycles.
  • Resource Lazy-Loading: The ChipApi class uses magic __get or direct instantiation for resources. Review lib/ChipApi.php to ensure resource objects are handled efficiently.
  • Dependency Removal: We have removed netresearch/jsonmapper. Confirm that the manual fromArray() implementations in lib/Model/ cover all edge cases previously handled by the library.

Is this PR warrant an automatic approval?

No. This is a foundational refactor that changes the error-handling contract, introduces a new major PHP requirement, and alters the core request architecture. It requires a thorough manual architectural review.

Images

Back-End or Front-End dependency tasks/PRs?

wzul and others added 24 commits May 13, 2026 14:46
- Update composer.json to require PHP ^8.0 (was >=7.2.0, which was
  incompatible with existing PHP 8 constructor property promotion)
- Fix implicitly nullable parameter warnings in Purchase trait by
  using explicit nullable types (?int)
Create domain-specific exceptions that map HTTP status codes to
meaningful error types:

- ChipApiException (base) — exposes response body via getResponseBody()
- AuthenticationException — 401 responses
- NotFoundException — 404 responses
- ValidationException — 422 responses with getErrors()
- ClientException — other 4xx responses
- ServerException — 5xx responses
Rewrite request() to catch Guzzle HTTP exceptions and throw
domain-specific exceptions based on status code. Add PSR-3 logger
injection for request/response observability. Support configurable
request timeout via the  array (defaults to 30s).
- phpstan.neon.dist: level 8 analysis for lib/ and tests/
- .php-cs-fixer.dist.php: PSR-12 + additional rules for lib/, tests/, examples/
Provide a fluent builder for constructing Purchase objects without
manually nesting ClientDetails, PurchaseDetails, and Product models.

Example:
     = PurchaseBuilder::create()
        ->brandId('brand_123')
        ->currency('MYR')
        ->clientEmail('test@example.com')
        ->addProduct('Widget', 5000, 2)
        ->build();
- Add model mapping tests (Purchase, PaymentMethods, Webhook, ClientDetails)
- Add exception handling tests for 401, 404, 422, 500
- Add logger integration test
- Add timeout configuration test
- Fix existing tests to pass correct types (string IDs, Purchase objects)
- Add jsonResponse() helper for type-safe JSON encoding in tests
- ci.yml: run tests on PHP 8.0-8.3 matrix, static analysis, code style
- pr-summary.yml: auto-generate PR descriptions via Ollama Cloud
- scripts/generate_pr_summary.py: Python script to call Ollama API
- README.md: rewrite with badges, quick-start, API reference, error
  handling, builder usage, logging, and development commands
- CONTRIBUTING.md: add contribution guidelines with test/style workflow
- CLAUDE.md: update with new commands and architecture details
Resolve conflicts and incorporate upstream changes:
- Add Billing API trait and models from main
- Add markAsPaid method to Purchase trait
- Add deleteWebhook method to Webhook trait
- Add getClients method to Client trait
- Add logos property to PaymentMethods model
- Add .env.example and test.php from main
- Keep our improvements: exceptions, logging, builder, tests, CI
- ci.yml: actions/checkout v4 → v6, actions/cache v4 → v5
- Add changelog.yml: validate CHANGELOG.md is updated on PRs touching lib/
- Add release.yml: create GitHub Releases from version tags using CHANGELOG.md
- Remove test.php development script (not part of test suite, uses real credentials)
- Add .env.example to .gitignore alongside existing entries
- Add ModelTest.php covering JsonSerializable and null-stripping for all models
- Add ExceptionTest.php with isolated exception unit tests
- Add negative webhook verification test (invalid signature returns false)
- Add billing API tests covering all 11 billing endpoints
- Add getClients() test
- Fix PHPStan level 8 errors in billing models and traits by adding property/return types
- Run php-cs-fixer across the entire codebase for consistent formatting

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- guzzlehttp/guzzle ^7.0 → ^7.9 (5 years of security fixes since 7.0)
- phpunit/phpunit ^9.0 → ^9.6 (EOL branch vs maintained branch)
- phpstan/phpstan ^1.10 → ^1.12 (bug fixes and improvements)

Installed versions confirmed: Guzzle 7.10.0, PHPUnit 9.6.34, PHPStan 1.12.33

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- PHP ^8.0 → ^8.1 with platform.php 8.1.0
- PHPUnit ^9.6 → ^10.5 (PHP 8.1 compatible)
- PHPStan ^1.12 → ^2.1 (major upgrade with better analysis)
- php-cs-fixer ^3.0 → ^3.95 (unlocked from 3.4.x PHP 8.0 limitation)
- CI matrix: removed PHP 8.0, updated static-analysis and code-style to 8.1
- Fixed remaining code style issues in example files

All 66 tests pass, PHPStan reports 0 errors, code style clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Document PHP 8.1 bump, PHPUnit 10, PHPStan 2, php-cs-fixer 3.95
- Document expanded test coverage, GitHub Actions workflows
- Document fixed PHPStan errors and composer.json validation

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- New traits: Account (balance, turnover), PublicKey, Statements
- Expanded Client trait: get, update, partial update, delete, recurring tokens
- Expanded Webhook trait: list, update, partial update
- Expanded Purchase trait: resend invoice
- Fixed PaymentMethod to accept optional query parameters
- New models: ClientRecurringToken, ClientRecurringTokenList, CompanyStatement,
  CompanyStatementList, WebhookList
- Added tests for all new endpoints and fixed currency to MYR

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Updated README.md, composer.json, and config.php for PHP 8.1
- Added examples for all new endpoints: Account, Statements, Client CRUD,
  Webhook Management, Purchase Builder
- Replaced raw curl in callback/webhook/public_key examples with SDK methods
- Added navigation links in index.php for all example categories

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Update PHP requirement in README from ^8.0 to ^8.1 (matching composer.json)
- Add documentation for all new endpoints: Account, Statements, PublicKey,
  Client CRUD, Webhook list/update, resendInvoice, PurchaseBuilder
- Fix CHANGELOG release date from 2025-05-13 to 2026-05-14

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Purchase: add notes, marked_as_paid, order_id, upsell_campaigns,
  referral_campaign_id, referral_code, referral_code_details,
  referral_code_generated, retain_level_details, can_retrieve,
  can_chargeback, can_reverse_chargeback, tags.
  Fix status_history to array, issued to string|null.
- PurchaseDetails: add shipping_options, payment_method_details,
  has_upsell_products, single_attempt, metadata.
- Product: add category, total_price_override. Fix quantity and tax_percent
  to string|null per spec.
- ClientDetails: add state, shipping_state, bank_account, bank_code.
- PaymentMethods: fix by_country, country_names, names to array with
  @phpstan-var for precise typing.
- PurchaseBuilder: cast quantity to string to match model type.
- ModelTest: update quantity values to strings.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
JsonMapper cannot parse array<...> syntax and treats it as a class name.
Use plain @var array for JsonMapper compatibility and @phpstan-var for
PHPStan level 8 precise typing.

- PaymentMethods::$logos: @var array<string, mixed>|null → @var array
- Purchase::$status_history: @var array<int, object> → @var array
- Purchase::$upsell_campaigns: @var array<int, mixed> → @var array
- PurchaseDetails::$shipping_options: @var array<int, mixed> → @var array

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This release contains breaking changes:
- PHP requirement raised from >=7.2.0 to ^8.1
- Model property type changes (Product::quantity/tax_percent to string,
  Purchase::issued to string|null, Purchase::status_history to array)
- Exception handling rewritten to throw domain-specific exceptions

Changes:
- CHANGELOG.md: rename 1.2.0 section to 2.0.0, update compare links
- MIGRATION.md: comprehensive guide covering PHP version, exception handling,
  model property type changes, new constructor parameter, new features
- README.md: update install version to ^2.0, add migration link
- examples/composer.json: update requirement to ^2.0.0

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…v2.0.0

- Replace trait-based ChipApi with resource objects (purchases, clients,
  webhooks, paymentMethods, account, statements, publicKey, billing)
- Add internal HTTP abstraction: ClientInterface, GuzzleClient, RetryClient
- Remove netresearch/jsonmapper dependency; add fromArray() to all models
- Add exponential backoff retry for 429/5xx responses
- Add pagination iterators for list endpoints (clients, webhooks, statements,
  billing templates, billing template clients)
- Create BillingResource with fromArray() on all billing models
- Rewrite tests for new resource-based API
- Update README, MIGRATION.md, and CHANGELOG for v2.0.0

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@wzul wzul requested a review from azuddin May 14, 2026 06:24
@wzul wzul merged commit f05c6b9 into main May 14, 2026
8 checks passed
@wzul wzul deleted the feature/sdk-improvements branch May 14, 2026 06:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants